﻿Imports System.Drawing.Drawing2D

Public Class ImageDitherer

    'Original image and thumb.
    '
    'Dithered image and thumb.
    'Ditherer settings.

    Public originalBitmap As Bitmap = Nothing

    Public width As Integer = 0
    Public height As Integer = 0

    Public standardisedBitmap As Bitmap = Nothing
    Public standardisedBitmapThumb As Bitmap = Nothing
    Public displayBitmapThumb As Bitmap = Nothing

    Public ditheredBitmap As ImageHolder = Nothing
    Public ditheredBitmapThumbForProcessing As ImageHolder = Nothing
    Public ditheredBitmapThumbForDisplay As ImageHolder = Nothing

    Public filterSettings As SelectedSettings = Nothing


    Public Shared Widening Operator CType(ByVal val As Bitmap) As ImageDitherer
        Return New ImageDitherer(val)
    End Operator

    Public Shared Widening Operator CType(ByVal val As ImageDitherer) As Bitmap
        Return val.originalBitmap
    End Operator

    Public Sub New()
    End Sub

    Public Sub New(ByVal image As Bitmap)
        width = image.Width
        height = image.Height
        setImage(image)
    End Sub

    Public Sub New(ByVal image As Bitmap, ByVal filter As SelectedSettings)
        width = image.Width
        height = image.Height
        setImage(image)
        setDither(filter)
    End Sub

    Public Sub New(ByVal image As Bitmap, ByVal width As Integer, ByVal height As Integer)
        Me.width = width
        Me.height = height
        setImage(image)
    End Sub

    Public Sub New(ByVal image As Bitmap, ByVal filter As SelectedSettings, ByVal width As Integer, ByVal height As Integer)
        Me.width = width
        Me.height = height
        setImage(image)
        setDither(filter)
    End Sub

    Public Sub setSize(ByVal width As Integer, ByVal height As Integer)
        Me.width = width
        Me.height = height
        makeStandardImage()
        processDither()
    End Sub

    Public Sub setImage(ByVal image As Bitmap)
        originalBitmap = image
        makeStandardImage()
        processDither()
    End Sub

    Public Sub setImageAndSize(ByVal image As Bitmap, ByVal width As Integer, ByVal height As Integer)
        Me.width = width
        Me.height = height
        originalBitmap = image
        makeStandardImage()
        processDither()
    End Sub

    Public Sub makeStandardImage()
        If originalBitmap Is Nothing Then Return
        standardisedBitmap = standardiseBitmap(resizeImage(originalBitmap, width, height))
        standardisedBitmapThumb = standardiseBitmap(newThumb(resizeImage(originalBitmap, width, height), 125, 100))
        displayBitmapThumb = standardiseBitmap(newThumb(resizeImage(originalBitmap, width, height), 250, 200))
    End Sub

    Public Sub setDither(ByVal filter As SelectedSettings)
        filterSettings = filter
        processDither()
    End Sub

    Public Sub lockBitmap()
        ditheredBitmap.lockBitmap()
        ditheredBitmapThumbForProcessing.lockBitmap()
    End Sub

    Public Sub LockBitmap(ByVal accessMode As Imaging.ImageLockMode)
        ditheredBitmap.lockBitmap(accessMode)
        ditheredBitmapThumbForProcessing.lockBitmap(accessMode)
    End Sub

    Public Sub unlockBitmap()
        ditheredBitmap.unlockBitmap()
        ditheredBitmapThumbForProcessing.unlockBitmap()
    End Sub

    Public Sub processDither()
        If filterSettings Is Nothing Or standardisedBitmap Is Nothing Then Return
        If filterSettings IsNot Nothing AndAlso (filterSettings.filterType <> "None" And filterSettings.filterType <> "") Then
            ditheredBitmap = filterSettings.filter.Apply(greyscaleImage(standardisedBitmap, filterSettings.greyR, filterSettings.greyG, filterSettings.greyB))
            ditheredBitmapThumbForProcessing = filterSettings.filter.Apply(greyscaleImage(standardisedBitmapThumb, filterSettings.greyR, filterSettings.greyG, filterSettings.greyB))
            ditheredBitmapThumbForDisplay = filterSettings.filter.Apply(greyscaleImage(standardiseBitmap(newThumb(resizeImage(originalBitmap, width, height), 250, 200)), filterSettings.greyR, filterSettings.greyG, filterSettings.greyB))
        Else
            ditheredBitmap = greyscaleImage(standardisedBitmap, filterSettings.greyR, filterSettings.greyG, filterSettings.greyB)
            ditheredBitmapThumbForProcessing = greyscaleImage(standardisedBitmapThumb, filterSettings.greyR, filterSettings.greyG, filterSettings.greyB)
            ditheredBitmapThumbForDisplay = greyscaleImage(standardiseBitmap(newThumb(resizeImage(originalBitmap, width, height), 250, 200)), filterSettings.greyR, filterSettings.greyG, filterSettings.greyB)
        End If
    End Sub

    Public Function greyscaleImage(ByVal image As Bitmap, ByVal r As Decimal, ByVal g As Decimal, ByVal b As Decimal) As Bitmap
        Dim gs = New AForge.Imaging.Filters.Grayscale(r, g, b)
        Return gs.Apply(image)
    End Function

    Public Function standardiseBitmap(ByVal source As Bitmap) As Bitmap
        Dim standardBitmapHandle = New Bitmap(source.Width, source.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb)
        ' Dim rect As New Rectangle(0, 0, source.Width, source.Height)
        Dim g As Graphics = Graphics.FromImage(standardBitmapHandle)
        'g.DrawImage(source, rect, 0, 0, source.Width, source.Height, GraphicsUnit.Pixel)
        g.DrawImage(source, 0, 0)
        g.Dispose()
        Return standardBitmapHandle
    End Function

    Public Function newThumb(ByVal image As Bitmap, ByVal width As Integer, ByVal height As Integer) As Image
        Dim ratio As Double = 0
        If image.Width > image.Height Then
            ratio = width / image.Width
        Else
            ratio = height / image.Height
        End If
        Dim myCallback As New System.Drawing.Image.GetThumbnailImageAbort(AddressOf ThumbnailCallback)
        Return image.GetThumbnailImage(image.Width * ratio, image.Height * ratio, myCallback, IntPtr.Zero)
    End Function

    Public Function ThumbnailCallback() As Boolean
        Return False
    End Function

    Public Function resizeImage(ByVal image As Image, ByVal newWidth As Integer, ByVal newHeight As Integer) As Bitmap
        'If image.Width = newWidth And image.Height = newHeight Then Return image
        Dim newImage As Image = New Bitmap(newWidth, newHeight)
        Using graphicsHandle As Graphics = Graphics.FromImage(newImage)
            graphicsHandle.InterpolationMode = InterpolationMode.HighQualityBicubic
            graphicsHandle.DrawImage(image, 0, 0, newWidth, newHeight)
        End Using
        Return newImage
    End Function

End Class
